package com.itheima.rpc.client.spring;

import com.itheima.rpc.annotation.HrpcRemote;
import com.itheima.rpc.proxy.ProxyFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * @desc spring的后置处理器，扫描自定义注解，生成代理对象
 * @author:ivan.liu
 */
@Component
@Slf4j
public class RpcAnnotationProcessor implements BeanPostProcessor, ApplicationContextAware {

    //动态代理生成工具类
    private ProxyFactory proxyFactory;

    /**
     * 初始化之后生成代理对象
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //获取bean的成员变量
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                //设置属性的private失效
                if(!field.isAccessible()){
                    field.setAccessible(true);
                }
                //如果有自定义注解，则生成代理对
                HrpcRemote hrpcRemote = field.getAnnotation(HrpcRemote.class);
                if(hrpcRemote!=null){
                    //生成代理对象
                    Object proxy = proxyFactory.newProxyInstance(field.getType());
                    log.info("客户端为{}生成的代理为:{}",field.getType().getName(),proxy);
                    //赋值
                    if(proxy!=null){
                        field.set(bean,proxy);
                    }
                }
            } catch (IllegalAccessException e) {
                log.error("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
            }
        }
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.proxyFactory = applicationContext.getBean(ProxyFactory.class);
    }
}
